home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / DEMON / RISCOS2 / TCP_131S.ARC / c / TCPOUT < prev    next >
Text File  |  1992-03-03  |  8KB  |  187 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7.  
  8. /* Send a segment on the specified connection. One gets sent only
  9.  * if there is data to be sent or if "force" is non zero
  10.  */
  11. void tcp_output(register struct tcb *tcb)
  12. {
  13.         struct pseudo_header ph;/* Pseudo-header for checksum calcs */
  14.         struct mbuf *hbp,*dbp;  /* Header and data buffer pointers */
  15.         int16 hsize;            /* Size of header */
  16.         struct tcp seg;         /* Local working copy of header */
  17.         int16 ssize;            /* Size of current segment being sent,
  18.                                  * including SYN and FIN flags */
  19.         int16 dsize;            /* Size of segment less SYN and FIN */
  20.         int16 usable;           /* Usable window */
  21.         int16 sent;             /* Sequence count (incl SYN/FIN) already in the pipe */
  22.  
  23.         if(tcb == NULLTCB)
  24.                 return;
  25.  
  26.         switch(tcb->state){
  27.         case LISTEN:
  28.         case CLOSED:
  29.                 return; /* Don't send anything */
  30.         }
  31.         for(;;){
  32.                 sent = (int16)(tcb->snd.ptr - tcb->snd.una);
  33.  
  34. #ifdef  notdef
  35.                 /* If this is a retransmission, send only the oldest segment
  36.                  * (first-only retransmission policy) -- OBSOLETED by cwind
  37.                  */
  38.                 if((tcb->flags & RETRAN) && sent != 0)
  39.                         break;
  40. #endif
  41.                 /* Don't send anything else until our SYN has been acked */
  42.                 if(sent != 0 && !(tcb->flags & SYNACK))
  43.                         break;
  44.  
  45.                 if(tcb->snd.wnd == 0){
  46.                         /* Allow only one closed-window probe at a time */
  47.                         if(sent != 0)
  48.                                 break;
  49.                         /* Force a closed-window probe */
  50.                         usable = 1;
  51.                 } else {
  52.                         /* usable window = offered window - unacked bytes in transit
  53.                          * limited by the congestion window
  54.                          */
  55.                         usable = min(tcb->snd.wnd,tcb->cwind) - sent;
  56.  
  57.                         /* John Nagle's "single outstanding segment" rule.
  58.                          * Allow only one segment in the pipeline unless there is enough
  59.                          * unsent data to form at least one maximum-sized segment.
  60.                          */
  61.                         if(sent != 0 && tcb->sndcnt - sent < tcb->mss){
  62.                                 usable = 0;
  63.                         }
  64. #ifdef  notdef
  65.                         /* Silly window avoidance. Don't send anything if the usable window
  66.                          * is less than a quarter of the offered window.
  67.                          * This test comes into play only when the offered window is at
  68.                          * least 4 times the MSS; otherwise Nagle's test is sufficient
  69.                          * to prevent SWS.
  70.                          */
  71.                         else if(usable < tcb->snd.wnd/4){
  72.                                 usable = 0;
  73.                         }
  74. #endif
  75.                 }
  76.                 /* Compute size of segment to send. This is either the usable
  77.                  * window, the mss, or the amount we have on hand, whichever is less.
  78.                  * (I don't like optimistic windows)
  79.                  */
  80.                 ssize = min(tcb->sndcnt - sent,usable);
  81.                 ssize = min(ssize,tcb->mss);
  82.                 dsize = ssize;
  83.  
  84.                 if(ssize == 0 && !(tcb->flags & FORCE))
  85.                         break;          /* No need to send anything */
  86.  
  87.                 tcb->flags &= ~FORCE;   /* Only one forced segment! */
  88.  
  89.                 seg.source = tcb->conn.local.port;
  90.                 seg.dest = tcb->conn.remote.port;
  91.  
  92.                 /* Set the SYN and ACK flags according to the state we're in. It is
  93.                  * assumed that if this segment is associated with a state transition,
  94.                  * then the state change will already have been made. This allows
  95.                  * this routine to be called from a retransmission timeout with
  96.                  * force=1.
  97.                  * If SYN is being sent, adjust the dsize counter so we'll
  98.                  * try to get the right amount of data off the send queue.
  99.                  */
  100.                 seg.flags = ACK; /* Every state except SYN_SENT */
  101.                 hsize = TCPLEN; /* Except when SYN being sent */
  102.                 seg.mss = 0;
  103.  
  104.                 switch(tcb->state){
  105.                 case SYN_SENT:
  106.                         seg.flags = 0;  /* Note fall-thru */
  107.                 case SYN_RECEIVED:
  108.                         if(tcb->snd.ptr == tcb->iss){
  109.                                 seg.flags |= SYN;
  110.                                 dsize--;
  111.                                 /* Also send MSS */
  112.                                 seg.mss = tcp_mss;
  113.                                 hsize = TCPLEN + MSS_LENGTH;
  114.                         }
  115.                         break;
  116.                 }
  117.                 seg.seq = tcb->snd.ptr;
  118.                 seg.ack = tcb->rcv.nxt;
  119.                 seg.wnd = tcb->rcv.wnd;
  120.                 seg.up = 0;
  121.  
  122.                 /* Now try to extract some data from the send queue.
  123.                  * Since SYN and FIN occupy sequence space and are reflected
  124.                  * in sndcnt but don't actually sit in the send queue,
  125.                  * dup_p will return one less than dsize if a FIN needs to be sent.
  126.                  */
  127.                 if(dsize != 0){
  128.                         if(dup_p(&dbp,tcb->sndq,sent,dsize) != dsize){
  129.                                 /* We ran past the end of the send queue; send a FIN */
  130.                                 seg.flags |= FIN;
  131.                                 dsize--;
  132.                         }
  133.                 } else
  134.                         dbp = NULLBUF;
  135.  
  136.                 /* If the entire send queue will now be in the pipe, set the
  137.                  * push flag
  138.                  */
  139.                 if(dsize != 0 && sent + ssize == tcb->sndcnt)
  140.                         seg.flags |= PSH;
  141.  
  142.                 /* If this transmission includes previously transmitted data,
  143.                  * snd.nxt will already be past snd.ptr. In this case,
  144.                  * compute the amount of retransmitted data and keep score
  145.                  */
  146.                 if(tcb->snd.ptr < tcb->snd.nxt)
  147.                         tcb->resent += min(tcb->snd.nxt - tcb->snd.ptr,ssize);
  148.  
  149.                 tcb->snd.ptr += ssize;
  150.                 /* If this is the first transmission of a range of sequence
  151.                  * numbers, record it so we'll accept acknowledgments
  152.                  * for it later
  153.                  */
  154.                 if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
  155.                         tcb->snd.nxt = tcb->snd.ptr;
  156.  
  157.                 /* Fill in fields of pseudo IP header */
  158.                 ph.source = tcb->conn.local.address;
  159.                 ph.dest = tcb->conn.remote.address;
  160.                 ph.protocol = TCP_PTCL;
  161.                 ph.length = hsize + dsize;
  162.  
  163.                 /* Generate TCP header, compute checksum, and link in data */
  164.                 if((hbp = htontcp(&seg,dbp,&ph)) == NULLBUF){
  165.                         free_p(dbp);
  166.                         return;
  167.                 }
  168.                 /* If we're sending some data or flags, start retransmission
  169.                  * and round trip timers if they aren't already running.
  170.                  */
  171.                 if(ssize != 0){
  172.                         tcb->timer.start = backoff(tcb->backoff) *
  173.                          (2 * tcb->mdev + tcb->srtt + MSPTICK) / MSPTICK;
  174.                         if(!run_timer(&tcb->timer))
  175.                                 start_timer(&tcb->timer);
  176.  
  177.                         /* If round trip timer isn't running, start it */
  178.                         if(!run_timer(&tcb->rtt_timer)){
  179.                                 start_timer(&tcb->rtt_timer);
  180.                                 tcb->rttseq = tcb->snd.ptr;
  181.                         }
  182.                 }
  183.                 ip_send(tcb->conn.local.address,tcb->conn.remote.address,
  184.                  TCP_PTCL,tcb->tos,0,hbp,ph.length,0,0);
  185.         }
  186. }
  187.